package locutor.draft.moc

import java.io.File

import scala.xml.{Document, Node}

import locutor.dg._

import scaup.Views._
import scaup.E

import scalaxx.diff.Command
import scalaxx.diff.Differ.{xmldiff => diff}

object MoC { 
  
  case class ℳ(val g: DG, val e: ℰ, val r: ℛ) {
    def ↩ (commands: List[Command]) = error("not yet implemented")
  }
  case class ℰ() extends E[Node]
  case class ℛ()  
  
  def dgOf(f: File): DG = DG(f/".dep")
  
  def parse(f: File) = xml.parsing.ConstructingParser.fromFile(f, true).document
  
  def infoset(f: File): (Document, ℳ) = (parse(f), ℳ(dgOf(f), ℰ(), ℛ()))
  
  def modelOf(d: Document): ℳ = error("not yet implemented")
  
  def ℰ (m: ℳ) = m.e
  def ℛ (m: ℳ) = m
  def Ḡ (m: ℳ) = new {
    def ↩ (commands: List[Command]) = new {
      def having(m: ℳ) = m ↩ commands
    }
  }
  
  /** MoC[CIA] workflow */
  def main(args: Array[String]): Unit = {
    
    // Given a file in two different versions.
    
    val f1: File = "dft/module/moc/aFileV1.xml".toFile
    val f2: File = "dft/module/moc/aFileV2.xml".toFile
    
    // In the first phase we retrieve the information set of f₁
    // 
    // An information set is a pair constituted of an AST of f₁ and a document model of f₁.
    //  
    // In contrast to common folklore, once built, /no/ additional information is added to the AST by
    // subsequent processing, e.g., semantic analysis.  Sensitive data -- in sense of change management --
    // potentially retrieved by semantic analysis is (already) represented within the corresponding
    // document model.
    //
    // A document model ℳ = <Ḡ, ℰ, ℛ> is a triple constituted of
    //  o a dependency graph Ḡ = <I, D>. Ḡ is a directed, classified, labeled multi-graph,
    //    where I is the set of INFOMs and D ⊆ I X I is the set of dependencies both classified.
    //  o a set of equiv-relations ℰ on Ḡ(I)      
    //  o a rule system ℛ = <ℙ, ℂ>, where ℙ denotes a set of propagation rules on Ḡ
    //    and ℂ a set of consistency rules for Ḡ.
    //
    // A dependency graph describes the dependencies of f₁, i.e. dependencies between INFOMs of f₁ as well as 
    // between INFOMs within other files.
    
    val (d1: Document, m: ℳ) = infoset(f1)  
    
    // In the second phase we compute the model-based changeset δ of d₁ with respect to d₂,
    // such that @(δ, d₁) = d₂ holds.
    //
    // Note: Think of ``@'' as apply or patch.    
    //
    // Note: The differencing algorithm uses ℰ only!
    //  
    // Note: At the moment a document model only consists of ℰ!  Current work on ↩, in particular,
    //       will justify the above defined triple.    

    val δ : List[Command] = diff(ℰ(m), d1, parse(f2))
    
    // In the third phase we compute the extended changeset Δ of d1
    // by rippling (↩) δ into Ḡ(ℳ) in consideration of ℛ(ℳ) (short ℳ ↩ δ),
    // such that δ ⊴ Δ, @(Δ|δ, d₁) = d₂ and @(Δ\δ, d₂) = d₃.    
    
    val Δ : List[Command] = Ḡ(m) ↩ δ having ℛ(m)
    assert(Δ == m ↩ δ)
    
    // The fourth and final phase is a preview 
    
    Δ partition (c => δ exists (_ == c)) match { case (localEffects, rippleEffects) =>
      assert(localEffects == δ)
      println("Changeset:\n"+localEffects)
      println("----")
      println("Ripple Effects:\n"+rippleEffects)
    }
  }
}
